package cc.owoo.godpen.analysis;

import cc.owoo.godpen.util.N;

/**
 * 字符串解析工具
 * Created by nimensei
 * 2022-05-16 上午 01:58
 **/
public class StringAnalysis {
    protected final char[] chars;// 需要解析的字符
    protected int index;// 当前解析位置
    private int plus;// 下一个字符的偏移量

    public StringAnalysis(char[] chars) {
        this.chars = chars;
    }

    /**
     * 指针是否还能继续下一个
     *
     * @return 指针是否还能继续下一个
     */
    public boolean hashNext() {
        if (getNextIndex() < chars.length)
            return true;
        index += plus;
        plus = 0;
        return false;
    }

    /**
     * 使下一个字符为当前字符的上一个字符
     */
    public void prev() {
        if (index > 0)
            plus = -1;
    }

    /**
     * 使下一个字符仍然为当前字符
     */
    public void reset() {
        plus = 0;
    }

    /**
     * 将下标移动到下一个
     */
    public char next() {
        char c = chars[index += plus];
        plus = 1;
        return c;
    }

    /**
     * 获取下一个字符的位置
     *
     * @return 当前下标位置
     */
    public int getNextIndex() {
        return index + plus;
    }

    /**
     * 获取当前下标位置
     *
     * @return 当前下标位置
     */
    public int getIndex() {
        return index;
    }

    /**
     * 设置当前下标位置
     *
     * @param index 下标
     */
    public void setIndex(int index) {
        this.index = index;
        plus = 0;
    }

    /**
     * 改变指针位置
     *
     * @param add 需要添加的值
     */
    public void indexAdd(int add) {
        index += add;
        plus = 0;
    }

    /**
     * 获取当前字符
     *
     * @return 当前字符
     */
    public char charAt() {
        return chars[index];
    }


    /**
     * 获取指定下标的字符
     *
     * @param index 字符下标
     * @return 当前字符
     */
    public char charAt(int index) {
        return chars[index];
    }

    /**
     * 从当前位置查找字符第一次出现的位置
     *
     * @param c 需要查找的字符
     * @return 字符第一次出现的下标
     */
    public int indexOf(char c) {
        for (int i = index; i < chars.length; i++)
            if (chars[i] == c)
                return i;
        return -1;
    }

    /**
     * 将指针位置移动至要查找的字符位置，如果没找到，则移动到最后一位
     *
     * @param c 需要查找的符号
     */
    public int nextIndexOf(char c) {
        while (hashNext())
            if (next() == c)
                break;
        return index;
    }

    /**
     * 从当前位置查找字符串第一次出现的位置
     *
     * @param string 需要查找的字符串
     * @return 字符串第一次出现的下标
     */
    public int indexOf(char[] string) {
        int len = chars.length;
        con:
        for (int i = index; i < len; i++) {
            for (int s = 0; s < string.length; s++)
                if (chars[i + s] != string[s])
                    continue con;
            return i;
        }
        return -1;
    }

    /**
     * 将指针位置移动至要查找的字符串位置，如果没找到，则移动到最后一位
     *
     * @param string 需要查找的字符串
     */
    public int nextIndexOf(char[] string) {
        next();
        index = indexOf(string);
        if (index == -1) {
            index = chars.length;
            return index;
        }
        int temp = index;
        index += string.length;
        plus = 0;
        return temp;
    }

    /**
     * 前缀匹配
     *
     * @param chars 需要匹配的字符串
     * @return 前缀是否为需要匹配的字符串
     */
    public boolean startsWith(char[] chars) {
        if (chars.length > this.chars.length - index)
            return false;
        for (int i = 0; i < chars.length; i++)
            if (chars[i] != this.chars[i + index])
                return false;
        return true;
    }

    /**
     * 返回下一个非空字符
     *
     * @param defaultCharacter 如果未找到，则返回这个默认字符
     * @return 如果下标超出边界则返回\0
     */
    public Character nextNotNull(Character defaultCharacter) {
        while (hashNext()) {
            if (next() > 32)
                return charAt();
        }
        return defaultCharacter;
    }

    /**
     * 返回下一个空字符
     *
     * @return 如果下标超出边界则返回null
     */
    public Character nextNull() {
        while (hashNext()) {
            if (next() <= 32)
                return charAt();
        }
        return null;
    }

    /**
     * 返回下一个名称，名称的命名规则为：不能包含任何空格和标点符号，如\t、[、-等
     *
     * @return 字符串
     */
    public String nextName() {
        int before = index;
        while (hashNext()) {
            char c = next();
            if (c <= 47 || c >= 58 && c <= 64 || c >= 91 && c <= 96 || c >= 123 && c <= 127)
                break;
        }
        return substring(before);
    }

    /**
     * 解析字符串
     *
     * @param end 结束符
     * @return 字符串
     */
    public String nextString(char end) {
        StringBuilder string = new StringBuilder();
        next();
        if (hashNext()) {
            index = N.parseEscape(string, chars, index, end);
            plus = 0;
        }
        return string.toString();
    }

    /**
     * 裁剪子串
     *
     * @param start 子串开始下标
     * @param end   子串结束下标
     * @return 裁剪之后的子串
     */
    public String substring(int start, int end) {
        char[] chars = substringArray(start, end);
        return chars == null ? "" : new String(chars);
    }

    /**
     * 裁剪字符出，从start到当前遍历的字符位置
     *
     * @param start 开始位置
     * @return 裁剪的字符串
     */
    public String substring(int start) {
        return substring(start, Math.min(index, chars.length));
    }

    /**
     * 裁剪子串数组
     *
     * @param start 字串开始下标
     * @param end   字串结束下标
     * @return 裁剪之后的子串数组
     */
    public char[] substringArray(int start, int end) {
        if (end <= start)
            return null;
        char[] chars = new char[end - start];
        System.arraycopy(this.chars, start, chars, 0, chars.length);
        return chars;
    }

    /**
     * 获取字符串长度
     *
     * @return 字符串长度
     */
    public int length() {
        return chars.length;
    }
}
